home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / HS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-28  |  18.4 KB  |  767 lines

  1. #ifdef MSDOS
  2. /* Interface driver for the DRSI PCPA or the Eagle 8530 boards for the IBM PC
  3.  * connected to a WA4DSY 56kbps modem. Uses polling-loop transfers with
  4.  * interrupts disabled for maximum speed.
  5.  *
  6.  * This driver is a bit of a kludge. A DMA-driven card and driver (e.g.,
  7.  * the PI) is much better, but this is better than nothing if all you have
  8.  * is a "dumb" 8530 card.
  9.  *
  10.  * Copyright 1991 Phil Karn, KA9Q
  11.  */
  12. #include "global.h"
  13. #ifdef HS
  14. #include <dos.h>
  15. #include "mbuf.h"
  16. #include "iface.h"
  17. #include "pktdrvr.h"
  18. #include "hs.h"
  19. #include "z8530.h"
  20. #include "trace.h"
  21. #include "pc.h"
  22. #include "proc.h"
  23. #include "devparam.h"
  24. #include "timer.h"
  25.  
  26. #if !defined(_lint)
  27. static char rcsid[] OPTIONAL = "$Id: hs.c,v 1.15 1996/12/29 02:47:22 root Exp root $";
  28. #endif
  29.  
  30. static void flushrx (int16 data);
  31. static void hdlcparam (struct hdlc *hp);
  32. static void hexint (struct hdlc *hp);
  33. static void hrxint (struct hdlc *hp);
  34. static int hs_stop (struct iface *iface);
  35. static int hs_raw (struct iface *iface,struct mbuf *bp);
  36. static void hs_tx (int unused,void *hp1,void *a);
  37. static int32 hs_ctl (struct iface *,int cmd,int set,int32 val);
  38. static void hstxoff (struct hdlc *hp);
  39. static void hstxon (struct hdlc *hp);
  40. static void htxint (struct hdlc *hp);
  41. static void init_delay (void);
  42. static void msdelay (void);
  43.  
  44. static struct hs Hs[NHS];
  45. static void (*Hshandle[])() = { hs0vec };
  46. static struct hdlc Hdlc[2*NHS];
  47. static int16 Nhs;
  48.  
  49. /* Master interrupt handler for the PC-100 card. All interrupts come
  50.  * here first, then are switched out to the appropriate routine.
  51.  */
  52. void
  53. hsint(dev)
  54. int dev;
  55. {
  56.     register char iv;
  57.     int16 hsbase;
  58.     register struct hdlc *hp;
  59.     
  60.     Hs[dev].ints++;
  61.     hsbase = Hs[dev].addr;
  62.  
  63. #ifdef    foo
  64.     outportb(hsbase+4,0x8+0x10);    /* HIT EAGLE INTACK */
  65.     (void)inportb(hsbase+CHANA+CTL,R0);
  66.     outportb(hsbase+4,0x8);        /***/
  67. #endif
  68.  
  69.     /* Read interrupt status from channel A */
  70.     while((iv = read_scc(hsbase+CHANA+CTL,R3)) != 0){
  71.         if(iv & CHARxIP){
  72.             /* Channel A Rcv Interrupt Pending */
  73.             hp = &Hdlc[2*dev];
  74.             hrxint(hp);
  75.         } else if(iv & CHATxIP){
  76.             /* Channel A Transmit Int Pending */
  77.             hp = &Hdlc[2*dev];
  78.             htxint(hp);
  79.         } else if(iv & CHAEXT){
  80.             /* Channel A External Status Int */
  81.             hp = &Hdlc[2*dev];
  82.             hexint(hp);
  83.         } else if(iv & CHBRxIP){
  84.             /* Channel B Rcv Interrupt Pending */
  85.             hp = &Hdlc[(2*dev)+1];
  86.             hrxint(hp);
  87.         } else if(iv & CHBTxIP){
  88.             /* Channel B Transmit Int Pending */
  89.             hp = &Hdlc[(2*dev)+1];
  90.             htxint(hp);
  91.         } else if(iv & CHBEXT){
  92.             /* Channel B External Status Int */
  93.             hp = &Hdlc[(2*dev)+1];
  94.             hexint(hp);
  95.         }
  96.         /* Reset interrupt pending state */
  97.         write_scc(hp->ctl,R0,RES_H_IUS);
  98.         outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  99.         outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  100.     }
  101.     outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  102.     outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  103. }
  104. /* HDLC SIO External/Status interrupts
  105.  * The only one that can happen in this driver is a DCD change
  106.  */
  107. static void
  108. hexint(hp)
  109. register struct hdlc *hp;
  110. {
  111.     struct mbuf *rcvbuf;
  112.     struct phdr phdr;
  113.     char *cp;
  114.     int cnt,data;
  115.     register int ctl;
  116.  
  117.     ctl = hp->ctl;
  118.     data = hp->data;
  119.     hp->exints++;
  120.  
  121.     /* Allocate a receive buffer */
  122.     if((rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(phdr))) == NULLBUF){
  123.         /* Alloc failed; refuse to proceed */
  124.         hp->nomem++;
  125.         write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  126.         write_scc(ctl,R0,RES_EXT_INT);
  127.         return;
  128.     }
  129.     /* Allow space for phdr descriptor on front */
  130.     cp = rcvbuf->data + sizeof(phdr);
  131.     cnt = 0;
  132.  
  133.     /* Disable DCDIE bit so we can track changes in DCD */
  134.     write_scc(ctl,R15,0);
  135.  
  136.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  137.     flushrx(data);
  138.     while((cnt = rx8530(ctl,data,cp,hp->bufsiz)) != -1){
  139.         if(cnt > 4){
  140.             /* Good frame */
  141.             hp->good++;
  142.             /* Toss crc */
  143.             rcvbuf->cnt = sizeof(phdr) + cnt - 1;
  144.             phdr.iface = hp->iface;
  145.             phdr.type = CL_AX25;
  146.             memcpy(rcvbuf->data,(char *)&phdr,sizeof(phdr));
  147.             enqueue(&Hopper,rcvbuf);
  148.             /* Replenish buffer */
  149.             rcvbuf = alloc_mbuf(hp->bufsiz + sizeof(phdr));
  150.         }
  151.         /* Start new buffer */
  152.         if(rcvbuf == NULLBUF)
  153.             break;    /* alloc failed */
  154.         cp = rcvbuf->data + sizeof(phdr);
  155.     }    
  156.     write_scc(ctl,R0,RES_EXT_INT);
  157.     write_scc(ctl,R15,DCDIE);    /* Re-enable DCD */
  158.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  159.  
  160.     /* Get rid of fragmentary buffer */
  161.     free_p(rcvbuf);
  162. }
  163. static void
  164. flushrx(data)
  165. register int16 data;
  166. {
  167.     register int i = 5;
  168.     while(i-- != 0)
  169.         (void)inportb(data);
  170. }
  171. /* HDLC receiver interrupt handler.
  172.  * Not used in this driver
  173.  */
  174. static void
  175. hrxint(hp)
  176. register struct hdlc *hp;
  177. {
  178. }
  179. /* HDLC transmit interrupt service routine
  180.  * Not used in this driver
  181.  */
  182. static void
  183. htxint(hp)
  184. register struct hdlc *hp;
  185. {
  186. }
  187.  
  188. /* (re)Initialize HDLC controller parameters */
  189. static void
  190. hdlcparam(hp)
  191. register struct hdlc *hp;
  192. {
  193.     char i_state;
  194.     register int16 ctl;
  195.  
  196.     /* Initialize 8530 channel for SDLC operation */
  197.     ctl = hp->ctl;
  198.     i_state = disable ();
  199.  
  200. #ifdef    foo
  201.     switch(ctl & 2){
  202.     case CHANA:
  203.         write_scc(ctl,R9,CHRA);    /* Reset channel A */
  204.         break;
  205.     case CHANB:
  206.         write_scc(ctl,R9,CHRB);    /* Reset channel B */
  207.         break;
  208.     }
  209.     kpause(1L);    /* Allow plenty of time for resetting */
  210. #endif
  211.  
  212.     /* Deselect interrupts for now */
  213.     write_scc(ctl,R1,0);
  214.     write_scc(ctl,R15,0);
  215.  
  216.     /* X1 clock, SDLC mode, Sync modes enable, parity disable */
  217.     write_scc(ctl,R4,X1CLK | SDLC | SYNC_ENAB);
  218.  
  219.     /* CRC preset 1, NRZ encoding, no active on poll, flag idle,
  220.      * flag on underrun, no loop mode, 8 bit sync
  221.      */
  222.     write_scc(ctl,R10,CRCPS|NRZ);
  223.  
  224.     /* 8530 gets both tx and rx clock from modem.
  225.      * By default, TRxC = transmit clock, RTxC = receive clock
  226.      * (swapped 11 Feb 1990 to use new DRSI wiring) UNLESS
  227.      * the 'r' parameter is specified
  228.      */
  229.     if(!hp->clkrev)
  230.         write_scc(ctl,R11,RCRTxCP | TCTRxCP);
  231.     else
  232.         write_scc(ctl,R11,RCTRxCP | TCRTxCP);
  233.  
  234.     /* Note: baud rate generator not used */
  235.  
  236.     /* Null out SDLC start address */
  237.     write_scc(ctl,R6,0);
  238.  
  239.     /* SDLC flag */
  240.     write_scc(ctl,R7,FLAG);
  241.  
  242.     /* DTR On, 8 bit TX chars, no break, TX enable, SDLC CRC,
  243.      * RTS off, TxCRC enable
  244.      */
  245.     write_scc(ctl,R5,DTR|Tx8|TxENAB|TxCRC_ENAB);
  246.  
  247.     /* 8 bit RX chars, auto enables off, no hunt mode, RxCRC enable,
  248.      * no address search, no inhibit sync chars, disable RX. Rx is
  249.      * started only by an actual DCD interrupt
  250.      */
  251.     write_scc(ctl,R3,RxENABLE|RxCRC_ENAB|Rx8);
  252.  
  253.     /* Dummy interrupt vector
  254.      * (This probably isn't necessary)
  255.      */
  256.     write_scc(ctl,R2,0);
  257.  
  258.     /* Enable only the external interrupts (modem interrupts) since
  259.      * polling is used for all actual tx/rx operations
  260.      */
  261.     write_scc(ctl,R1,EXT_INT_ENAB);
  262.  
  263.     /* Enable only DCD interrupts */
  264.     write_scc(ctl,R15,DCDIE);
  265.  
  266.     /* No reset, status low, master int enable, enable lower chain,
  267.      * no vector
  268.      */
  269.     write_scc(ctl,R9,MIE|NV);
  270.  
  271.     restore(i_state);
  272. }
  273. /* Attach a high speed iterface to the system
  274.  * argv[0]: hardware type, must be "hs"
  275.  * argv[1]: I/O address, e.g., "0x380"
  276.  * argv[2]: vector, e.g., "2"
  277.  * argv[3]: mode, must be "ax25"
  278.  * argv[4]: interface base label, e.g., "drsi0". Driver appends "a" and "b".
  279.  * argv[5]: receiver packet buffer size in bytes
  280.  * argv[6]: maximum transmission unit, bytes
  281.  * argv[7]: keyup delay, milliseconds
  282.  * argv[8]: persistence value, 0-255
  283.  * argv[9]: "r" to reverse sense of clock leads (optional)
  284.  */
  285. int
  286. hs_attach(argc,argv,p)
  287. int argc;
  288. char *argv[];
  289. void *p;
  290. {
  291.     register struct iface *if_hsa,*if_hsb;
  292.     struct hdlc *hp;
  293.     int dev;
  294.     char *cp;
  295.  
  296.     if(Nhs >= NHS){
  297.         tputs("Too many hs controllers\n");
  298.         return -1;
  299.     }
  300.     if(if_lookup(argv[4]) != NULLIF){
  301.         tprintf(Existingiface,argv[4]);
  302.         return -1;
  303.     }
  304.     dev = Nhs++;
  305.  
  306.     /* Initialize hardware-level control structure */
  307.     Hs[dev].addr = htoi(argv[1]);
  308.     Hs[dev].vec = htoi(argv[2]);
  309.  
  310.     /* Save original interrupt vector */
  311.     Hs[dev].save.vec = getirq(Hs[dev].vec);
  312.     /* Set new interrupt vector */
  313.     if(setirq(Hs[dev].vec,Hshandle[dev]) == -1){
  314.         tprintf("IRQ %u out of range\n",Hs[dev].vec);
  315.         Nhs--;
  316.         return -1;
  317.     }
  318.     /* Create interface structures and fill in details */
  319.     if_hsa = (struct iface *)callocw(1,sizeof(struct iface));
  320.     if_hsb = (struct iface *)callocw(1,sizeof(struct iface));
  321.  
  322.     if_hsa->addr = if_hsb->addr = Ip_addr;
  323.     cp = mallocw(strlen(argv[4])+2);
  324.     strcpy(cp,argv[4]);
  325.     strcat(cp,"a");
  326.     if_hsa->name = cp;
  327.     cp = mallocw(strlen(argv[4])+2);
  328.     strcpy(cp,argv[4]);
  329.     strcat(cp,"b");
  330.     if_hsb->name = cp;
  331.     if_hsb->iface_metric = 1;
  332.     if_hsb->mtu = if_hsa->mtu = atoi(argv[6]);
  333.     if_hsb->type = if_hsa->type = CL_AX25;
  334.     if_hsa->dev = 2*dev;
  335.     if_hsb->dev = 2*dev + 1;
  336.     if_hsb->stop = if_hsa->stop = hs_stop;
  337.     if_hsb->output = if_hsa->output = ax_output;
  338.     if_hsb->raw = if_hsa->raw = hs_raw;
  339.     if_hsa->ioctl = if_hsb->ioctl = hs_ctl;
  340.  
  341.     if(strcmp(argv[3],"ax25") == 0){
  342.         if(Mycall[0] == '\0'){
  343.             tputs("set mycall first\n");
  344.             free((char *)if_hsa);
  345.             free((char *)if_hsb);
  346.             return -1;
  347.         }        
  348.         if_hsb->send = if_hsa->send = ax_send;
  349.         if(if_hsb->hwaddr == NULLCHAR)
  350.             if_hsb->hwaddr = mallocw(AXALEN);
  351.         memcpy(if_hsb->hwaddr,Mycall,AXALEN);
  352.         if(if_hsb->ipcall == NULLCHAR)
  353.             if_hsb->ipcall = mallocw(AXALEN);
  354.         memcpy(if_hsb->ipcall,Mycall,AXALEN);
  355.         if(if_hsa->hwaddr == NULLCHAR)
  356.             if_hsa->hwaddr = mallocw(AXALEN);
  357.         memcpy(if_hsa->hwaddr,Mycall,AXALEN);
  358.         if(if_hsa->ipcall == NULLCHAR)
  359.             if_hsa->ipcall = mallocw(AXALEN);
  360.         memcpy(if_hsa->ipcall,Mycall,AXALEN);
  361.     } else {
  362.         tprintf("Mode %s unknown for interface %s\n",
  363.             argv[3],argv[4]);
  364.         free((char *)if_hsa);
  365.         free((char *)if_hsb);
  366.         return -1;
  367.     }
  368.     if_hsa->next = if_hsb;
  369.     if_hsb->next = Ifaces;
  370.     Ifaces = if_hsa;
  371.  
  372.     write_scc(Hs[dev].addr+CHANA+CTL,R9,FHWRES);
  373.     hp = &Hdlc[2*dev+1];
  374.     hp->ctl = Hs[dev].addr + CHANB + CTL;
  375.     hp->data = Hs[dev].addr + CHANB + DATA;
  376.     hp->bufsiz = atoi(argv[5]);
  377.     if(argc > 7)
  378.         hp->txdelay = atol(argv[7]);
  379.     else
  380.         hp->txdelay = 15L;
  381.     if(argc > 8)
  382.         hp->p = atoi(argv[8]);
  383.     else
  384.         hp->p = 64;
  385.     if(argc > 9 && argv[9][0] == 'r')
  386.         hp->clkrev = 1;
  387.     else
  388.         hp->clkrev = 0;
  389.     hp->iface = if_hsb;
  390.     hdlcparam(hp);
  391.     if_hsa->txproc = newproc("hs_tx",1024,hs_tx,0,hp,NULL,0);
  392.  
  393.     hp = &Hdlc[2*dev];
  394.     hp->ctl = Hs[dev].addr + CHANA + CTL;
  395.     hp->data = Hs[dev].addr + CHANA + DATA;
  396.     hp->bufsiz = atoi(argv[5]);
  397.     hp->txdelay = Hdlc[2*dev+1].txdelay;
  398.     hp->p = Hdlc[2*dev+1].p;
  399.     if(argc > 9 && argv[9][0] == 'r')
  400.         hp->clkrev = 1;
  401.     else
  402.         hp->clkrev = 0;
  403.     hp->iface = if_hsa;
  404.     hdlcparam(hp);
  405.     if_hsb->txproc = newproc("hs_tx",1024,hs_tx,0,hp,NULL,0);
  406.  
  407.     outportb(Hs[dev].addr + 4,0x08);    /*EAGLE INT GATE */
  408.     /* Clear mask (enable interrupt) in 8259 interrupt controller */
  409.     maskon(Hs[dev].vec);
  410.  
  411.     /* Initialize timing delay loop */
  412.     init_delay();
  413.     return 0;
  414. }
  415. static int
  416. hs_stop(iface)
  417. struct iface *iface;
  418. {
  419.     int dev;
  420.  
  421.     dev = iface->dev;
  422.     if(dev & 1)
  423.         return -1;    /* Valid only for the first device */
  424.     dev >>= 1;    /* Convert back into hs number */
  425.  
  426.     /* Turn off interrupts */
  427.     maskoff(Hs[dev].vec);
  428.  
  429.     /* Restore original interrupt vector */
  430.     setirq(Hs[dev].vec,Hs[dev].save.vec);
  431.  
  432.     /* Force hardware reset */
  433.     write_scc(Hs[dev].addr + CHANA+CTL,R9,FHWRES);
  434.     return 0;
  435. }
  436. /* Send raw packet */
  437. static int
  438. hs_raw(iface,bp)
  439. struct iface *iface;
  440. struct mbuf *bp;
  441. {
  442.  
  443.     struct hdlc *hp;
  444.  
  445.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  446.     iface->rawsndcnt++;
  447.     iface->lastsent = secclock();
  448.     hp = &Hdlc[iface->dev];
  449.     hp->txpkts++;
  450.     enqueue(&hp->txq,bp);    /* Put on queue for hs_tx process */
  451.     return 0;
  452. }
  453.  
  454. /* High speed transmit process */
  455. void
  456. hs_tx(unused,hp1,a)
  457. int unused;
  458. void *hp1;
  459. void *a;    /* Unused */
  460. {
  461.     struct mbuf *bp,*nbp;
  462.     register int16 cnt;
  463.     register char *cp;
  464.     int16 ctl,data;
  465.     int txon = 0;    /* Transmitter on/off state */
  466.     struct hdlc *hp;
  467.     int i;
  468.  
  469.     hp = (struct hdlc *)hp1;
  470.     ctl = hp->ctl;
  471.     data = hp->data;
  472.  
  473.     for(;;){
  474.         /* Wait for work */
  475.         while(hp->txq == NULLBUF){
  476.             if(txon){
  477.                 /* No more frames, shut down tx */
  478.                 hstxoff(hp);
  479.                 txon = 0;
  480.                 /* Hold off to give other guy a chance to
  481.                  * respond
  482.                  */
  483.                 hp->deftime = msclock() + hp->txdelay + 500;
  484.             }
  485.             kwait(&hp->txq);
  486.         }
  487.         bp = dequeue(&hp->txq);
  488.         cnt = len_p(bp);
  489.         /* If buffer isn't contiguous (which is almost always
  490.          * the case) copy it to a new buffer for speed
  491.          */
  492.         if(bp->next != NULLBUF){
  493.             if((nbp = copy_p(bp,cnt)) == NULLBUF){
  494.                 hp->nomem++;
  495.                 free_p(bp);
  496.                 continue;
  497.             }
  498.             free_p(bp);
  499.             bp = nbp;
  500.         }
  501.         cp = bp->data;
  502.         /* Turn transmitter on if necessary */
  503.         if(!txon){
  504.             hstxon(hp);
  505.             txon = 1;
  506.         } else {
  507.             /* Else wait another txd for receiver to get ready again */
  508.             for(i=hp->txdelay;i != 0;i--)
  509.                 msdelay();
  510.         }
  511.         /* Initialize transmitter CRC */
  512.         write_scc(ctl,R0,RES_Tx_CRC);
  513.         for(;;){
  514.             /* Wait for the transmitter to become ready */
  515.             while(!(inportb(ctl) & Tx_BUF_EMP))
  516.                 ;
  517.             if(cnt-- == 0)
  518.                 break;
  519.             outportb(data,*cp++); /* Send the character */
  520.         }
  521.         write_scc(ctl,R0,RES_EOM_L);    /* Allow CRC generation */
  522.  
  523.         /* End of frame. Wait for TxEOM to go high, indicating start of
  524.          * CRC transmission. Note that we don't reset the transmit
  525.          * interrupt pending flag as one ordinarily would, since we're
  526.          * not using tx interrupts.
  527.          */
  528.         while(!(inportb(ctl) & TxEOM))
  529.             ;
  530.  
  531.         free_p(bp);
  532.     }
  533. }
  534.  
  535. /* Turn on high speed transmitter. Does p-persistence, then sends a dummy
  536.  * frame to allow for keyup delay. Returns with transmitter on and interrupts
  537.  * disabled
  538.  */
  539. static void
  540. hstxon(hp)
  541. struct hdlc *hp;
  542. {
  543.     int16 ctl;
  544.     int i;
  545.     long ca;
  546.     int32 t;
  547.  
  548.     ctl = hp->ctl;
  549.  
  550.     /* Defer logic. Wait until deftime is in the past (so we
  551.      * defer to any overheard CTS messages) AND the p-persistence
  552.      * dice roll succeeds. The computation of ca allows for clock
  553.      * rollover (which happens every 49+ days).
  554.      */
  555.     for(;;){
  556.         t = msclock();
  557.         ca = hp->deftime - t;
  558.         if(ca > 0){
  559.             kpause(ca);
  560.             continue;
  561.         }
  562.         hp->deftime = t;    /* Keep from getting too old */
  563.         if((rand() & 0xff) > uchar(hp->p)){
  564.             kpause((long)MSPTICK);
  565.             continue;
  566.         }
  567.         break;
  568.     }
  569.     /* Prevent distractions. In particular, block off the DCD interrupt
  570.      * so we don't hear our own carrier and hang in the interrupt handler!
  571.      * Note that simply disabling CPU interrupts isn't enough since
  572.      * the call to kpause will block and the kernel will re-enable
  573.      * them.
  574.      */
  575.     write_scc(ctl,R9,0);    /* Disable all SCC interrupts */
  576.     (void)disable ();        /* Return value is always 1 */
  577.  
  578.     /* Turn on carrier, enable transmitter */
  579.     write_scc(ctl,R5,TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR);
  580.  
  581.     /* Delay for keyup interval */
  582.     for(i=hp->txdelay;i != 0;i--)
  583.         msdelay();
  584.  
  585. }
  586. /* Turn transmitter off at the end of a series of frames */
  587. static void
  588. hstxoff(hp)
  589. struct hdlc *hp;
  590. {
  591.     int cnt;
  592.     int16 ctl,data;
  593.  
  594.     ctl = hp->ctl;
  595.     data = hp->data;
  596.     /* To allow the SCC buffering to drain, we begin a dummy frame,
  597.      * then abort it
  598.      */
  599.     for(cnt=5;cnt != 0;cnt--){
  600.         while(!(inportb(ctl) & Tx_BUF_EMP))
  601.             ;
  602.         outportb(data,0);
  603.     }
  604.     write_scc(ctl,R0,SEND_ABORT);
  605.  
  606.     /* Turn off carrier and disable transmitter */
  607.     write_scc(ctl,R5,TxCRC_ENAB | Tx8 | DTR);
  608.     /* Re-Enable SCC interrupts */
  609.     write_scc(ctl,R9,MIE|NV);        
  610.     restore(1);    /* Turn interrupts back on */
  611. }
  612.  
  613. int
  614. dohs(argc,argv,p)
  615. int argc;
  616. char *argv[];
  617. void *p;
  618. {
  619.     register int i;
  620.     register struct hdlc *hp;
  621.  
  622.     for(i=0;i<2*Nhs;i++){
  623.         hp = &Hdlc[i];
  624.         if(tprintf("port %d: txpkts %lu ints %lu rxpkts %lu rxbytes %lu nomem %lu toobig %lu crcerr %lu aborts %lu overrun %lu\n",
  625.          i,hp->txpkts,hp->exints,hp->good,hp->rxbytes,
  626.          hp->nomem,hp->toobig,hp->crcerr,hp->aborts,
  627.          hp->overrun) == EOF)
  628.             break;
  629.     }
  630.     return 0;
  631. }
  632. static int32
  633. hs_ctl(iface,cmd,set,val)
  634. struct iface *iface;
  635. int cmd;
  636. int set;
  637. int32 val;
  638. {
  639.     register struct hdlc *hp;
  640.     int32 t,ca;
  641.  
  642.     hp = &Hdlc[iface->dev];
  643.     switch(cmd){
  644.     case PARAM_TXDELAY:    /* Tx keyup delay */
  645.         if(set)
  646.             hp->txdelay = val;
  647.         return hp->txdelay;
  648.     case PARAM_PERSIST:
  649.         if(set)
  650.             hp->p = val;
  651.         return uchar(hp->p);
  652.     case PARAM_MUTE:
  653.         /* Mute transmitter for specified # of ms */
  654.         if(set){
  655.             if(val == -1){
  656.                 /* Special case for duration of a CTS */
  657.                 val = hp->txdelay + 500;
  658.             }
  659.             hp->deftime = msclock() + val;
  660.         }
  661.         t = msclock();
  662.         ca = hp->deftime - t;
  663.         if(ca < 0){
  664.             hp->deftime = t;
  665.             ca = 0;
  666.         }
  667.         return ca;
  668.     }
  669.     return -1;
  670. }
  671. #ifdef    notdef        /* replaced with assembler in 8530.asm */
  672. /* Read data from the 8530 receiver.
  673.  * Returns when either a good frame is received, or when carrier drops.
  674.  * If a good frame is received, the length is returned; otherwise -1.
  675.  */
  676. int
  677. rx8530(ctl,data,buf,bufsize)
  678. int16 ctl,data;
  679. char *buf;
  680. int16 bufsize;
  681. {
  682.     int cnt = 0;
  683.     register char status;
  684.     char error;
  685.     register char *cp = buf;
  686.  
  687.     for(;;){
  688.         status = inportb(ctl);
  689.         if(!(status & DCD)){
  690.             cnt = -1;
  691.             break;
  692.         } else if(status & BRK_ABRT){
  693.             cp = buf;
  694.             cnt = 0;
  695.         } else if(status & Rx_CH_AV){
  696.             /* Receive character is ready, get it */
  697.             *cp++ = inportb(data);
  698.             if(++cnt > bufsize){
  699.                 /* Buffer overflow, start again */
  700.                 write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  701.                 cp = buf;
  702.                 cnt = 0;
  703.             }
  704.         } else if((error = read_scc(ctl,R1)) & END_FR){
  705.             if(!(error & CRC_ERR))
  706.                 break;    /* Good frame! */
  707.             /* Bad frame, start again */
  708.             cp = buf;
  709.             cnt = 0;
  710.         }
  711.     }
  712.     return cnt;
  713. }
  714. #endif
  715.  
  716. static int32 Del_const;
  717.  
  718. /* Find the value of Del_const that will cause one execution of mloop()
  719.  * to take one millisecond
  720.  */
  721. static void
  722. init_delay()
  723. {
  724.     int32 start,delay;
  725.     register int i,j;
  726.     int success = 0;
  727.  
  728.     /* Start with small value to make things tolerable on slow machines */
  729.     Del_const = 10;
  730.     tprintf("Del_const = %lu\n",Del_const);
  731.     /* Limit the number of iterations in case we don't converge */
  732.     for(i=0;i<5;i++){
  733.         start = msclock();
  734.         for(j=0;j<1000;j++)
  735.             msdelay();
  736.         delay = msclock()-start;
  737.         tprintf("delay %lu\n",delay);
  738.         if(delay == 0){
  739.             /* Too fast for accurate measurement on coarse clk */    
  740.             Del_const *= 10;
  741.             tprintf("Del_const = %lu\n",Del_const);
  742.             continue;
  743.         }
  744.         Del_const = (Del_const * 1000)/delay;
  745.         tprintf("Del_const = %lu\n",Del_const);
  746.         if(delay > 950 && delay < 1050){
  747.             success = 1;
  748.             break;    /* Within 1 tick - Close enough */
  749.         }
  750.     }
  751.     if(!success)
  752.         tputs("HS: Warning: auto delay set failed\n");
  753. }
  754. /* Delay for one millisecond (once calibrated by init_delay()) */
  755. static void
  756. msdelay()
  757. {
  758.     int32 i;
  759.  
  760.     for(i=Del_const;i !=0;i--)
  761.         ;
  762. }
  763.  
  764. #endif /* HS */
  765. #endif /* MSDOS */
  766.  
  767.